home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 8
/
QRZ Ham Radio Callsign Database - Volume 8.iso
/
pc
/
files
/
t_unix
/
j109lxa4.tar
/
unix.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-04
|
14KB
|
740 lines
/*
* Timers and process delays work differently under POSIX. The entire system
* is driven on a single select() call, which uses the timeout to detect alarms
* and the file descriptors to detect input. An itimer is used to allow
* keyboard input to continue during lengthy activities --- which I tried to
* avoid for portability reasons, but it behaves *real* ugly otherwise.
* Especially when LakeSW.ampr.org lets 350K of SMTP mail pile up...
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include "hardware.h"
#ifdef M_UNIX
#include <time.h>
#include <sys/select.h>
#else
#include <sys/time.h>
#endif
#include "timer.h"
#include "proc.h"
#include "unixtm.h"
#include "socket.h"
#ifdef NO_GETTOD
#include <sys/timeb.h>
#endif
#ifdef M_UNIX
#ifndef bzero
/* stupid bug in SCO 3.2.2 (is there any other kind for them?) */
#define bzero(s,n) memset((s),0,(n))
#endif
#endif
/* avoid collision with libc */
#define psignal j_psignal
/* and undo a collision avoidance, since we need the real one */
#undef malloc
#undef free
extern void *malloc __ARGS((size_t));
extern void free __ARGS((void *));
/* Don't use this yet... something's still calling malloc() directly */
#undef LMCHECK /* TEST memory allocation checker */
struct io
{
struct io *next;
int fd;
void *event;
};
char Hashtab[256];
int Tick;
int Keyboard;
int32 Clock;
static int __istate = 1;
static struct timeval Starttime;
static struct io *Events;
static int Shell;
/*****************************************************************************\
* Miscellanous functions not found in Unix *
\*****************************************************************************/
unsigned long
filelength(fd)
int fd;
{
static struct stat sb;
if (fstat(fd, &sb) == -1)
return 0;
return sb.st_size;
}
#ifdef NEED_STRCASECMP
int
strcasecmp(s1, s2)
register char *s1, *s2;
{
while (*s1 && *s2 && tolower(*s1) == tolower(*s2))
s1++, s2++;
return tolower(*s1) - tolower(*s2);
}
#endif
#ifdef NEED_STRNCASECMP
int
strncasecmp(s1, s2, n)
register char *s1, *s2;
int n;
{
while (n && *s1 && *s2 && tolower(*s1) == tolower(*s2))
s1++, s2++, n--;
return n? tolower(*s1) - tolower(*s2): 0;
}
#endif
char *
strupr(s)
char *s;
{
register char *p = s;
while (*p)
*p = toupper(*p), p++;
return s;
}
char *
strlwr(s)
char *s;
{
register char *p = s;
while (*p)
*p = tolower(*p), p++;
return s;
}
char *
stpcpy(d, s)
register char *d;
register const char *s;
{
while (*s)
*d++ = *s++;
*d = '\0';
return d;
}
char *
itoa(n, buf, base)
int n, base;
char *buf;
{
if (base != 10)
tprintf("WARNING: itoa() passed radix %d\n", base);
sprintf(buf, "%d", n);
return buf;
}
/* This was in assembler, I assume for speed. */
int16
hash_ip(ipaddr)
long ipaddr;
{
int h;
h = ((ipaddr >> 16) & 0xFFFF) ^ (ipaddr & 0xFFFF);
return Hashtab[((h >> 8) & 0xFF) ^ (h & 0xFF)];
}
/*****************************************************************************\
* Memory interface *
\*****************************************************************************/
#ifdef LMCHECK
/*
* We track memory allocation via hash buckets. This is a fixed-size hash
* table with variable-sized buckets: we hash an address by taking some bits
* from it, and store the result in a slot in the bucket.
*/
#define NMWHASH 4096 /* number of hash buckets - s/b power of 2 */
#define LOGNMWH 12 /* log2(NMWHASH) */
#define NMWHSHIFT 8 /* ptr shift for hashing */
#define NMWHSLOT 32 /* initial slots in bucket */
struct hbucket
{
void **ptr;
int nptr;
};
static struct hbucket MWhashtab[NMWHASH];
static void
mwhash(void *p)
{
register struct hbucket *h;
int i;
h = MWhashtab + (((unsigned long) p >> NMWHSHIFT) & (NMWHASH - 1));
if (!h->nptr)
{
h->ptr = malloc(NMWHSLOT * sizeof *h->ptr);
memset(h->ptr, 0, NMWHSLOT * sizeof *h->ptr);
i = 0;
}
else
{
for (i = 0; i < h->nptr; i++)
{
if (!h->ptr[i])
break;
}
if (i == h->nptr)
{
h->ptr = realloc(h->ptr, (h->nptr + NMWHSLOT) * sizeof *h->ptr);
memset(h->ptr + h->nptr, 0, NMWHSLOT * sizeof *h->ptr);
h->nptr += NMWHSLOT;
}
}
h->ptr[i] = p;
}
static int
mwunhash(void *p)
{
register struct hbucket *h;
int i;
h = MWhashtab + (((unsigned long) p >> NMWHSHIFT) & (NMWHASH - 1));
for (i = h->nptr; i--; )
{
if (h->ptr[i] == p)
break;
}
if (i == -1)
return 0;
h->ptr[i] = 0;
return 1;
}
#endif
void *
mallocw(unsigned size)
{
void *p;
if (!(p = malloc(size)))
where_outta_here(1);
#ifdef LMCHECK
mwhash(p);
#endif
return p;
}
void *
callocw(cnt, size)
unsigned cnt, size;
{
void *p;
if (!(p = malloc(size * cnt)))
where_outta_here(1);
#ifdef LMCHECK
mwhash(p);
#endif
memset(p, 0, size * cnt);
return p;
}
void
j_free(void *p)
{
#ifdef LMCHECK
if (!mwunhash(p))
{
printf("\r\7WARNING: free()ing unknown pointer %lx\r\n",
(unsigned long) p);
return;
}
#endif
free(p);
}
#if 0
/*
* these should by rights try to determine the available VM... oh, well
*/
unsigned long
availmem()
{
#ifdef linux
return 0xC0000000 - (unsigned long) sbrk(0);
#else
return 0x80000000 - (unsigned long) sbrk(0);
#endif
}
unsigned long
farcoreleft()
{
#ifdef linux
return 0xC0000000 - (unsigned long) sbrk(0);
#else
return 0x80000000 - (unsigned long) sbrk(0);
#endif
}
unsigned long
getss()
{
return 0;
}
#endif
/*****************************************************************************\
* Interrupt management - null *
\*****************************************************************************/
int
istate()
{
return __istate;
}
int
dirps()
{
sigset_t s;
int ops;
if (__istate)
{
sigemptyset(&s);
sigaddset(&s, SIGALRM);
sigprocmask(SIG_BLOCK, &s, (sigset_t *) 0);
}
ops = __istate;
__istate = 0;
return ops;
}
void
restore(ps)
int ps;
{
sigset_t s;
if (__istate != ps)
{
sigemptyset(&s);
sigaddset(&s, SIGALRM);
sigprocmask((ps? SIG_UNBLOCK: SIG_BLOCK), &s, (sigset_t *) 0);
}
__istate = ps;
}
/*****************************************************************************\
* Date and time functions *
\*****************************************************************************/
long
secclock()
{
#ifdef NO_GETTOD
static struct timeb t;
ftime(&t);
return t.time - Starttime.tv_sec - (Starttime.tv_usec > t.millitm * 1000);
#else
static struct timezone tz;
static struct timeval tv;
gettimeofday(&tv, &tz);
return tv.tv_sec - Starttime.tv_sec - (Starttime.tv_usec > tv.tv_usec);
#endif
}
long
msclock()
{
#ifdef NO_GETTOD
static struct timeb t;
ftime(&t);
t.millitm *= 1000;
if (t.millitm < Starttime.tv_usec)
{
t.millitm += 1000000;
t.time--;
}
return (t.time - Starttime.tv_sec) * 1000 +
(t.millitm - Starttime.tv_usec) / 1000;
#else
static struct timezone tz;
static struct timeval tv;
gettimeofday(&tv, &tz);
if (tv.tv_usec < Starttime.tv_usec)
{
tv.tv_usec += 1000000;
tv.tv_sec--;
}
return (tv.tv_sec - Starttime.tv_sec) * 1000 +
(tv.tv_usec - Starttime.tv_usec) / 1000;
#endif
}
static void
init_time(void)
{
#ifdef NO_GETTOD
struct timeb t;
ftime(&t);
Starttime.tv_sec = t.time;
Starttime.tv_usec = t.millitm * 1000;
#else
struct timezone tz;
gettimeofday(&Starttime, &tz);
#endif
}
void
gettime(tp)
struct time *tp;
{
struct tm *tm;
#ifdef NO_GETTOD
static struct timeb tb;
ftime(&tb);
tm = localtime(&tb.time);
tp->ti_hund = tb.millitm / 10;
#else
static struct timeval tv;
static struct timezone tz;
gettimeofday(&tv, &tz);
tm = localtime(&tv.tv_sec);
tp->ti_hund = tv.tv_usec / 10000;
#endif
tp->ti_hour = tm->tm_hour;
tp->ti_min = tm->tm_min;
tp->ti_sec = tm->tm_sec;
}
void
getdate(dp)
struct date *dp;
{
struct tm *tm;
#ifdef NO_GETTOD
static struct timeb tb;
ftime(&tb);
tm = localtime(&tb.time);
#else
static struct timeval tv;
static struct timezone tz;
gettimeofday(&tv, &tz);
tm = localtime(&tv.tv_sec);
#endif
dp->da_year = tm->tm_year + 1900;
dp->da_mon = tm->tm_mon + 1;
dp->da_day = tm->tm_mday;
}
long
dostounix(dp, tp)
struct date *dp;
struct time *tp;
{
static struct tm tm;
struct tm *tx;
long now;
tm.tm_year = dp->da_year - 1900;
tm.tm_mon = dp->da_mon - 1;
tm.tm_mday = dp->da_day;
tm.tm_hour = tp->ti_hour;
tm.tm_min = tp->ti_min;
tm.tm_sec = tp->ti_sec;
/* This desperately needs to be fixed. How? */
time(&now);
tx = localtime(&now);
tm.tm_isdst = tx->tm_isdst;
return mktime(&tm);
}
/*****************************************************************************\
* Timers, I/O and scheduling *
\*****************************************************************************/
void
register_io(fd, event)
int fd;
void *event;
{
struct io *evp;
if (!(evp = mallocw(sizeof *evp)))
{
tprintf("register_io: no memory for event\n");
where_outta_here(1);
}
evp->fd = fd;
evp->event = event;
evp->next = Events;
Events = evp;
}
void
unregister_io(fd)
int fd;
{
struct io *evp, *evc;
for (evp = 0, evc = Events; evc->fd != fd; evp = evc, evc = evc->next)
;
if (!evc)
{
tprintf("unregister_io: unknown fd\n");
return;
}
if (evp)
evp->next = evc->next;
else
Events = evc->next;
j_free(evc);
}
static void
ouch(int sig)
{
struct sigaction sa;
sa.sa_handler = SIG_DFL;
sa.sa_flags = 0;
sigaction(SIGSEGV, &sa, (struct sigaction *) 0);
#ifdef SIGBUS
sigaction(SIGBUS, &sa, (struct sigaction *) 0);
#endif
if (fork() == 0)
{
sigaction(sig, &sa, (struct sigaction *) 0);
raise(sig);
}
detach_all_asy();
exit(1);
}
static void
ding(int i)
{
extern struct timer *Timers;
static struct timeval tv;
struct timeval *tvp;
static fd_set fds;
struct io *evp;
long oclock;
/* do pending output */
if (!i)
{
tflush();
rflush();
}
/* collect input events to wait on */
FD_ZERO(&fds);
for (evp = Events; evp; evp = evp->next)
FD_SET(evp->fd, &fds);
/* get time until next timer; if zero, fake a very large one */
/* if we have a nonzero argument, we're a timer tick; poll, don't block */
if (i)
{
tv.tv_sec = tv.tv_usec = 0;
tvp = &tv;
}
else if (!Timers)
tvp = 0;
else
{
tv.tv_sec = (Timers->expiration - Clock) * MSPTICK;
if (tv.tv_sec <= 0)
tv.tv_sec = 0;
tv.tv_usec = (tv.tv_sec % 1000) * 1000;
tv.tv_sec /= 1000;
tvp = &tv;
}
/* check for I/O */
select(FD_SETSIZE, &fds, 0, 0, tvp);
/* signal events for pending I/O */
for (evp = Events; evp; evp = evp->next)
{
if (FD_ISSET(evp->fd, &fds))
psignal(evp->event, 1);
}
/* run any due timers */
psignal(&Tick, 1);
/* and update the system time */
oclock = Clock;
Clock = msclock() / MSPTICK;
Tick = Clock - oclock;
}
static void
init_tick(void)
{
struct sigaction sa;
struct itimerval it;
sa.sa_flags = 0;
sa.sa_handler = ding;
sigaction(SIGALRM, &sa, (struct sigaction *) 0);
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = MSPTICK * 1000;
it.it_value = it.it_interval;
setitimer(ITIMER_REAL, &it, (struct itimerval *) 0);
}
static void
deinit_tick(void)
{
struct itimerval it;
it.it_interval.tv_sec = it.it_interval.tv_usec = 0;
it.it_value = it.it_interval;
setitimer(ITIMER_REAL, &it, (struct itimerval *) 0);
}
void
init_sys(int no_itimer)
{
struct sigaction sa;
init_time();
register_io(0, &Keyboard);
sa.sa_handler = ouch;
sa.sa_flags = 0;
sigaction(SIGSEGV, &sa, (struct sigaction *) 0);
#ifdef SIGBUS
sigaction(SIGBUS, &sa, (struct sigaction *) 0);
#endif
if (!no_itimer)
init_tick();
}
void
deinit_sys()
{
deinit_tick();
unregister_io(0);
}
void
giveup()
{
/* suspend heartbeat */
deinit_tick();
/* block for I/O */
ding(0);
/* and reactivate the tick */
init_tick();
}
#ifdef SHELL
int
doshell(int argc, char **argv, void *p)
{
struct sigaction sa, old_int, old_quit;
int ac, pid;
int pi[2];
char *av[4];
/*
* Under *ix, one would expect ! or shell to work like in other *ix
* programs. Since we don't really want to emulate DOS doshell()'s
* special handling for argv[1] == "/c" anyway :-) we will handle
* this properly.
*
* argc < 2: ${SHELL:-/bin/sh}
* >= 2: concatenate and /bin/sh -c it (NOT $SHELL)!
*/
if (!sm_usestdio())
{
tprintf("Not running on NOS console\n");
return 1;
}
if (pipe(pi) == -1)
{
tprintf("Can't create pipe for subprocess\n");
return 1;
}
switch (pid = fork())
{
case -1:
tprintf("Fork failed\n");
return 1;
case 0:
close(pi[0]);
ac = 1;
if (argc > 1 || !(av[0] = getenv("SHELL")))
av[0] = "/bin/sh";
if (argc > 1)
{
av[ac++] = "-c";
av[ac++] = argv[1];
}
av[ac] = 0;
execv(av[0], av);
_exit(1);
default:
close(pi[1]);
iosuspend();
unregister_io(0);
register_io(pi[0], &Shell);
/* signal handling... */
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = SIG_IGN;
sigaction(SIGINT, &sa, &old_int);
sigaction(SIGQUIT, &sa, &old_quit);
pwait(&Shell);
sigaction(SIGQUIT, &old_quit, 0);
sigaction(SIGINT, &old_int, 0);
unregister_io(pi[0]);
close(pi[0]);
register_io(0, &Keyboard);
ioresume();
}
return 0;
}
#endif